package ca.unbc.cpsc672.fuzzy;

import java.util.Collection;
import java.util.LinkedList;

import ca.unbc.cpsc672.fuzzy.rule.IfThenRule;

/**
 * A collection of Fuzzy Rules, used for fuzzy inference
 * 
 * @author xi
 * 
 */
public class RuleSet {
	private LinkedList<IfThenRule> ruleList = new LinkedList<>();
	private String name;

	public RuleSet(String name) {
		this.name = name;
	}

	public void addRule(IfThenRule rule) {
		ruleList.add(rule);
	}
	
	public void removeRule(IfThenRule rule) {
		ruleList.remove(rule);
	}

	/**
	 * Fuzzy inference. Steps: <br>
	 * Step 1. Fuzzify Inputs<br>
	 * Step 2. Apply Fuzzy Operator<br>
	 * Step 3. Apply Implication Method<br>
	 * Step 4. Aggregate All Outputs<br>
	 * Step 5. Defuzzify<br>
	 * 
	 * @param iptx
	 *            input value for the output fuzzy functions, one value for one
	 *            input fuzzy set
	 * 
	 * @return the mu(y) for the output functions
	 * 
	 * @see <a
	 *      href="MatLab">http://www.mathworks.com/help/fuzzy/fuzzy-inference-process.html</a>
	 */
	public double infer(double... iptx) {
		// Step 1 ~ Step 3
		double max = 0;
		for (IfThenRule rule : ruleList) {
			rule.setInput(iptx);
			max = Math.max(max, rule.getRange());
		}
		double d = 0; // sum(mu * y)
		double n = 0; // sum(mu)
		// integral
		for (double y = 0; y < max; y += 0.01) {
			// Step 4. Aggregate All Outputs
			double mu = 0;
			for (IfThenRule rule : ruleList) {
				mu = Math.max(mu, rule.calcImplicationFunction(y));
			}

			d += mu * y;
			n += mu;
		}
		// Step 5. Defuzzify -- center of gravity
		double cog = d / n;
		return cog;
	}

	public String toCSVString() {
		StringBuffer sb = new StringBuffer();
		for (IfThenRule rule : ruleList) {
			sb.append(name).append(",");
			sb.append(rule.toCSVString()).append(",\n");
		}

		return sb.toString();
	}

	public String getName() {
		return name;
	}

	public Collection<IfThenRule> getRules() {
		return ruleList;
	}
}
